package com.pb.wkflow.api.service.impl;

import com.alibaba.fastjson.JSON;
import com.pb.infra.oth.entity.common.Result;
import com.pb.infra.oth.service.BaseService;
import com.pb.infra.oth.util.UserInfo;
import com.pb.wkflow.api.annotation.GlobalWorkflowAnnotation;
import com.pb.wkflow.api.annotation.WfTaskAnnotationService;
import com.pb.wkflow.api.config.ErrorMessageConstants;
import com.pb.wkflow.api.controller.assembler.ProcTaskAssembler;
import com.pb.wkflow.api.controller.request.ProcessTaskRequest;
import com.pb.wkflow.api.controller.response.TaskResponse;
import com.pb.wkflow.api.entity.CompleteTaskEntity;
import com.pb.wkflow.api.entity.MyApplyTaskEntity;
import com.pb.wkflow.api.entity.TodoTaskEntity;
import com.pb.wkflow.api.entity.WfSysProcInfoEntity;
import com.pb.wkflow.api.query.CompleteTaskQuery;
import com.pb.wkflow.api.query.MyApplyTaskQuery;
import com.pb.wkflow.api.query.TodoTaskQuery;
import com.pb.wkflow.api.service.ProcTaskService;
import com.pb.wkflow.api.service.WfSysProcInfoService;
import com.pb.wkflow.core.camunda.bpmn.instance.VoteWork;
import com.pb.wkflow.core.config.Constants;
import com.pb.wkflow.core.config.DeleteReasonConstants;
import com.pb.wkflow.core.handler.QueryHandler;
import com.pb.wkflow.core.handler.QueryResultHandler;
import com.pb.wkflow.core.service.*;
import com.pb.wkflow.core.utils.AssertUtils;
import com.pb.wkflow.core.utils.DateUtils;
import com.pb.wkflow.core.utils.StringUtils;
import com.pb.wkflow.core.utils.WorkflowThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.camunda.bpm.engine.history.HistoricProcessInstance;
import org.camunda.bpm.engine.history.HistoricTaskInstance;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.task.Task;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.camunda.bpm.model.bpmn.instance.FlowNode;
import org.camunda.bpm.model.bpmn.instance.ParallelGateway;
import org.camunda.bpm.model.bpmn.instance.UserTask;
import org.camunda.bpm.model.xml.instance.ModelElementInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @author 苗益辉
 * @date 2022/9/20 15:47
 */
@Slf4j
@Service
public class ProcTaskServiceImpl extends BaseService implements ProcTaskService {

    @Autowired
    WorkflowTaskService workflowTaskService;

    @Autowired
    WorkflowInstanceService workflowInstanceService;

    @Autowired
    WorkflowDefinitionService workflowDefinitionService;

    @Autowired
    WorkFlowEngineService workFlowEngineService;

    @Autowired
    QueryHandler queryHandler;

    @Autowired
    WfSysProcInfoService wfSysProcInfoService;

    @Autowired
    WorkflowBpmnService workflowBpmnService;

    @Autowired
    GlobalWorkflowAnnotation workflowAnnotation;

    /**
     * 查询待办列表
     * @param pageNum 页码
     * @param pageSize 页数
     * @param request 请求
     * @return Result
     */
    @Override
    public Result findToDoList(Integer pageNum, Integer pageSize, ProcessTaskRequest request) {
        UserInfo userInfo = this.getCurrentUserInfo();
        TodoTaskQuery taskQuery = ProcTaskAssembler.createTodoTaskQuery(request, userInfo);
        return queryHandler.commonPageQuery(taskQuery, pageNum, pageSize,
                (QueryResultHandler<TodoTaskEntity, TodoTaskEntity>) entity -> {
                    entity.setCreateTime(DateUtils.dataStrFormat(entity.getCreateTime(), "yyyy-MM-dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss"));
                    entity.setProcessStartTime(DateUtils.dataStrFormat(entity.getProcessStartTime(), "yyyy-MM-dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss"));
                    return entity;
                });
    }

    /**
     * 查询待办总数
     * @return Result
     */
    @Override
    public Result queryTodoCount() {
        UserInfo userInfo = this.getCurrentUserInfo();
        TodoTaskQuery taskQuery = ProcTaskAssembler.createTodoTaskQuery(new ProcessTaskRequest(), userInfo);
        long count = taskQuery.getCount();
        Map<String, Object> result = new HashMap<>();
        result.put("count", count);
        return Result.ok(result);
    }

    @Override
    public Result findHasDoneList(Integer pageNum, Integer pageSize, ProcessTaskRequest request) {
        UserInfo userInfo = this.getCurrentUserInfo();
        CompleteTaskQuery taskQuery = ProcTaskAssembler.createCompleteTaskQuery(request, userInfo);
        return queryHandler.commonPageQuery(taskQuery, pageNum, pageSize,
                (QueryResultHandler<CompleteTaskEntity, CompleteTaskEntity>) entity -> {
                    entity.setCreateTime(DateUtils.dataStrFormat(entity.getCreateTime(), "yyyy-MM-dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss"));
                    entity.setProcessStartTime(DateUtils.dataStrFormat(entity.getProcessStartTime(), "yyyy-MM-dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss"));
                    entity.setProcessEndTime(DateUtils.dataStrFormat(entity.getProcessEndTime(), "yyyy-MM-dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss"));
                    return entity;
                });
    }

    @Override
    public Result findMyApplyList(Integer pageNum, Integer pageSize, ProcessTaskRequest request) {
        UserInfo userInfo = this.getCurrentUserInfo();
        MyApplyTaskQuery taskQuery = ProcTaskAssembler.createMyApplyTaskQuery(request, userInfo);
        return queryHandler.commonPageQuery(taskQuery, pageNum, pageSize,
                (QueryResultHandler<MyApplyTaskEntity, MyApplyTaskEntity>) entity -> {
                    entity.setProcessStartTime(DateUtils.dataStrFormat(entity.getProcessStartTime(), "yyyy-MM-dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss"));
                    entity.setProcessEndTime(DateUtils.dataStrFormat(entity.getProcessEndTime(), "yyyy-MM-dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss"));
                    return entity;
                });
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public TaskResponse submitTask(ProcessTaskRequest request, String processStatus) {
        String userId = this.getCurrentUserId();
        AssertUtils.notEmpty(request.getTaskId(), ErrorMessageConstants.TASK_ID_NOE_NULL);
        //判断任务是否被领取
        workflowTaskService.checkAndClaimTask(userId, request.getTaskId());
        Task task = workflowTaskService.findTask(request.getTaskId());
        if (request.getLocalVariables() != null) {
            workflowTaskService.setTaskVariableLocal(task.getId(), request.getLocalVariables());
        }
        //领取任务
        workflowTaskService.claimTask(task.getId(), userId);
        request.setProcessInstanceId(task.getProcessInstanceId());
        //提交任务
        workflowTaskService.submitTask(request);
        HistoricProcessInstance processInstance = workflowInstanceService
                .queryHistoryProcessInstance(task.getProcessInstanceId());
        TaskResponse.TaskResponseBuilder taskResponse = TaskResponse.builder();
        taskResponse.taskId(task.getId());
        taskResponse.taskName(task.getName());
        taskResponse.taskDefineKey(task.getTaskDefinitionKey());
        taskResponse.processDefineId(task.getProcessDefinitionId());
        taskResponse.processInstanceId(task.getProcessInstanceId());
        if (processInstance.getEndTime() == null) {
            //如果提交后流程未结束
            taskResponse.isEnd(Constants.Flag.FALSE);
            // 更新流程状态
            wfSysProcInfoService.update(task.getProcessInstanceId(), processStatus,
                    request.getGlobalVariables(), Constants.Flag.FALSE);
            WfSysProcInfoEntity wfSysProcInfoEntity = getProcInfo(request.getProcessInstanceId(),request.getComment());
            WfTaskAnnotationService wfTaskAnnotationService = workflowAnnotation.getService(processInstance.getProcessDefinitionKey());
            wfTaskAnnotationService.submitTask(wfSysProcInfoEntity);
        } else {
            //如果提交后流程结束
            taskResponse.isEnd(Constants.Flag.TRUE);
            // 更新流程状态
            wfSysProcInfoService.update(task.getProcessInstanceId(), DeleteReasonConstants.COMPLETE,
                    request.getGlobalVariables(), Constants.Flag.TRUE);
            WfSysProcInfoEntity wfSysProcInfoEntity = getProcInfo(request.getProcessInstanceId(),request.getComment());
            WfTaskAnnotationService wfTaskAnnotationService = workflowAnnotation.getService(processInstance.getProcessDefinitionKey());
            wfTaskAnnotationService.completeTask(wfSysProcInfoEntity);
        }
        return taskResponse.build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public TaskResponse refuseTask(ProcessTaskRequest request) {
        String userId = this.getCurrentUserId();
        AssertUtils.notEmpty(request.getTaskId(), ErrorMessageConstants.TASK_ID_NOE_NULL);
        Task task = workflowTaskService.findTask(request.getTaskId());
        AssertUtils.notNull(task, ErrorMessageConstants.TASK_NOE_EXIST);
        //判断是否是会签，如果是会签的话，则提交
        BpmnModelInstance modelInstance = workflowDefinitionService.findModel(task.getProcessDefinitionId());
        String multiFlag = workflowDefinitionService.getIsMulti(modelInstance, task.getTaskDefinitionKey());
        workflowTaskService.checkAndClaimTask(userId, request.getTaskId());
        TaskResponse.TaskResponseBuilder taskResponseBuilder = TaskResponse.builder();
        //是会签
        if ("true".equals(multiFlag)) {
            if (request.getLocalVariables() == null) {
                request.setLocalVariables(new HashMap<>());
                request.getLocalVariables().put(Constants.VOTE_OPTION, Constants.VoteOption.VOTE_OPTION_AGAINST);
            }
            workflowTaskService.setTaskVariableLocal(task.getId(), request.getLocalVariables());
            //设置当前任务的审批信息
            WorkflowThreadLocalUtil.put("deleteReasonTaskId", task.getId());
            WorkflowThreadLocalUtil.put("deleteReason", DeleteReasonConstants.REFUSE);
            //领取任务
            workflowTaskService.claimTask(task.getId(), userId);
            request.setProcessInstanceId(task.getProcessInstanceId());
            //提交任务
            workflowTaskService.submitTask(request);
            taskResponseBuilder.taskId(task.getId());
            taskResponseBuilder.taskName(task.getName());
            taskResponseBuilder.taskDefineKey(task.getTaskDefinitionKey());
            taskResponseBuilder.processDefineId(task.getProcessDefinitionId());
            taskResponseBuilder.processInstanceId(task.getProcessInstanceId());
            //判断当前提交后流程是否结束
            HistoricProcessInstance processInstance = workflowInstanceService
                    .queryHistoryProcessInstance(task.getProcessInstanceId());
            //如果结束了，则判断是否是会签
            if (processInstance.getEndTime() != null) {
                taskResponseBuilder.isEnd(Constants.Flag.TRUE);
                // 更新流程状态
                wfSysProcInfoService.update(task.getProcessInstanceId(), DeleteReasonConstants.REFUSE,
                        null, Constants.Flag.TRUE);
            } else {
                wfSysProcInfoService.update(task.getProcessInstanceId(), DeleteReasonConstants.PROCESS,
                        null, Constants.Flag.FALSE);
                taskResponseBuilder.isEnd(Constants.Flag.FALSE);
            }
        } else {
            //不是会签，走终止流程
            workFlowEngineService.refuseProcess(task.getProcessInstanceId(), request.getComment(), task.getId(), userId);
            taskResponseBuilder.taskId(task.getId());
            taskResponseBuilder.taskName(task.getName());
            taskResponseBuilder.taskDefineKey(task.getTaskDefinitionKey());
            taskResponseBuilder.processDefineId(task.getProcessDefinitionId());
            taskResponseBuilder.processInstanceId(task.getProcessInstanceId());
            taskResponseBuilder.isEnd(Constants.Flag.TRUE);
            //更新流程状态
            wfSysProcInfoService.update(task.getProcessInstanceId(), DeleteReasonConstants.REFUSE,
                    null, Constants.Flag.TRUE);
            HistoricProcessInstance processInstance = workflowInstanceService
                    .queryHistoryProcessInstance(task.getProcessInstanceId());
            WfSysProcInfoEntity wfSysProcInfoEntity = getProcInfo(request.getProcessInstanceId(),request.getComment());
            WfTaskAnnotationService wfTaskAnnotationService = workflowAnnotation.getService(processInstance.getProcessDefinitionKey());
            wfTaskAnnotationService.refuseTask(wfSysProcInfoEntity);
        }
        return taskResponseBuilder.build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public TaskResponse terminateTask(ProcessTaskRequest request) {
        String userId = this.getCurrentUserId();
        AssertUtils.notEmpty(request.getTaskId(), ErrorMessageConstants.TASK_ID_NOE_NULL);
        Task task = workflowTaskService.findTask(request.getTaskId());
        AssertUtils.notNull(task, ErrorMessageConstants.TASK_NOE_EXIST);
        workflowTaskService.checkAndClaimTask(userId, request.getTaskId());
        workFlowEngineService.terminateProcess(task.getProcessInstanceId(), request.getComment(), task.getId(), userId);
        TaskResponse.TaskResponseBuilder taskResponseBuilder = TaskResponse.builder();
        taskResponseBuilder.taskId(task.getId());
        taskResponseBuilder.taskName(task.getName());
        taskResponseBuilder.taskDefineKey(task.getTaskDefinitionKey());
        taskResponseBuilder.processInstanceId(task.getProcessInstanceId());
        taskResponseBuilder.processDefineId(task.getProcessDefinitionId());
        taskResponseBuilder.isEnd(Constants.Flag.TRUE);
        TaskResponse taskResponse = taskResponseBuilder.build();
        //更新流程状态
        wfSysProcInfoService.update(task.getProcessInstanceId(), DeleteReasonConstants.TERMINATE,
                null, Constants.Flag.TRUE);
        HistoricProcessInstance processInstance = workflowInstanceService
                .queryHistoryProcessInstance(task.getProcessInstanceId());
        WfSysProcInfoEntity wfSysProcInfoEntity = getProcInfo(request.getProcessInstanceId(),request.getComment());
        WfTaskAnnotationService wfTaskAnnotationService = workflowAnnotation.getService(processInstance.getProcessDefinitionKey());
        wfTaskAnnotationService.terminateTask(wfSysProcInfoEntity);
        return taskResponse;
    }

    /**
     * 撤回上一个任务
     * @param request request
     * @return TaskResponse
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public TaskResponse backPreTask(ProcessTaskRequest request) {
        String userId = this.getCurrentUserId();
        AssertUtils.notEmpty(request.getTaskId(), ErrorMessageConstants.TASK_ID_NOE_NULL);
        Task task = workflowTaskService.findTask(request.getTaskId());
        AssertUtils.notNull(task, ErrorMessageConstants.TASK_NOE_EXIST);
        workflowTaskService.checkAndClaimTask(userId, request.getTaskId());
        BpmnModelInstance bpmnModelInstance = workflowDefinitionService.findModel(task.getProcessDefinitionId());
        UserTask userTask = bpmnModelInstance.getModelElementById(task.getTaskDefinitionKey());
        //当前节点之前的用户节点
        List<UserTask> previousUserTasks = getPreviousUserTask(userTask);
        List<String> nextActivityIds = new ArrayList<>();
        List<String> cancelActivityIds = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(previousUserTasks)) {
            //遍历已完成的任务节点，获取当前节点之前的用户节点
            List<HistoricTaskInstance> taskInstances = workflowInstanceService
                    .queryFinishTaskInstance(task.getProcessInstanceId());
            for (HistoricTaskInstance taskInstance : taskInstances) {
                for (UserTask previousUserTask : previousUserTasks) {
                    if (previousUserTask.getId().equals(taskInstance.getTaskDefinitionKey())) {
                        nextActivityIds.add(taskInstance.getTaskDefinitionKey());
                    }
                }
                if (CollectionUtils.isNotEmpty(nextActivityIds)) {
                    UserTask nextUserTask = bpmnModelInstance.getModelElementById(nextActivityIds.get(0));
                    //如果节点存在输出节点，且输出节点只有一个
                    if (CollectionUtils.isNotEmpty(nextUserTask.getOutgoing())
                            && nextUserTask.getOutgoing().size() == 1) {
                        FlowNode target = nextUserTask.getOutgoing().iterator().next().getTarget();
                        //如果上一个节点为并行网关，获取并行网关的前置节点
                        if (target instanceof ParallelGateway) {
                            nextActivityIds.clear();
                            List<UserTask> previousUserTask = getPreviousUserTask(target);
                            for (UserTask item : previousUserTask) {
                                nextActivityIds.add(item.getId());
                            }
                        }
                    }
                    if (userTask.getPreviousNodes().list() != null
                            && userTask.getPreviousNodes().list().size() == 1
                            && userTask.getPreviousNodes().list().get(0) instanceof ParallelGateway) {
                        //退出并行节点外，需要同时取消并行节点中的其他任务
                        List<Task> currentTasks = workflowTaskService.findTaskList(task.getProcessInstanceId());
                        for (Task currentTask : currentTasks) {
                            cancelActivityIds.add(currentTask.getTaskDefinitionKey());
                        }
                    } else {
                        //非并行
                        cancelActivityIds.add(userTask.getId());
                    }
                    break;
                }
            }
        }
        AssertUtils.notEmpty(nextActivityIds, "无法退回上一步");
        TaskResponse.TaskResponseBuilder taskResponseBuilder = TaskResponse.builder();
        if (CollectionUtils.isNotEmpty(cancelActivityIds)) {
            taskResponseBuilder.cancelActivityIds(cancelActivityIds);
        }
        taskResponseBuilder.nextActivityIds(nextActivityIds);
        taskResponseBuilder.activityId(task.getTaskDefinitionKey());
        taskResponseBuilder.processInstanceId(task.getProcessInstanceId());
        taskResponseBuilder.userId(userId);
        taskResponseBuilder.taskId(task.getId());
        taskResponseBuilder.taskName(task.getName());
        taskResponseBuilder.taskDefineKey(task.getTaskDefinitionKey());
        taskResponseBuilder.comment(request.getComment());
        taskResponseBuilder.variables(request.getGlobalVariables());
        TaskResponse taskResponse = taskResponseBuilder.build();
        workFlowEngineService.backTask(taskResponse, DeleteReasonConstants.REBACK);
        List<HistoricTaskInstance> firstTask = workflowInstanceService.queryFirstHistoryTaskInstance(task.getProcessInstanceId());
        String processStatus = DeleteReasonConstants.REBACK;
        if (CollectionUtils.isNotEmpty(firstTask)) {
            for (String nextActivityId : nextActivityIds) {
                // 如果回退的节点是首节点
                if (firstTask.get(0).getTaskDefinitionKey().equals(nextActivityId)) {
                    processStatus = DeleteReasonConstants.REBACK2FIRST;
                }
            }
        }
        // 更新流程状态
        wfSysProcInfoService.update(task.getProcessInstanceId(), processStatus,
                null, Constants.Flag.FALSE);

        return taskResponse;
    }

    /**
     * 收回已办任务
     * @param request request
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public TaskResponse reBackTask(ProcessTaskRequest request) {
        String userId = this.getCurrentUserId();
        String taskId = request.getTaskId();
        AssertUtils.notEmpty(taskId, "撤回失败，任务id不能为空");
        HistoricTaskInstance taskInstance = workflowTaskService.findHistoricTask(taskId);
        String taskDefineKey = taskInstance.getTaskDefinitionKey();
        AssertUtils.notNull(taskInstance, "撤回失败，任务不存在");
        AssertUtils.notTrue(taskInstance.getEndTime() != null, "撤回失败，当前任务还未提交");
        //本人收回
        AssertUtils.notTrue(userId.equals(taskInstance.getAssignee()), "撤回失败，您没有权限处理该任务");
        ProcessInstance instance = workflowInstanceService.findByProcessInstanceId(taskInstance.getProcessInstanceId());
        AssertUtils.notTrue(instance != null, "撤回失败，流程已结束");
        BpmnModelInstance bpmnModelInstance = workflowDefinitionService.findModel(taskInstance.getProcessDefinitionId());

        //获取撤回任务的bpmn信息，判断是否为会签
        ModelElementInstance modelElementInstance = bpmnModelInstance.getModelElementById(taskDefineKey);
        VoteWork voteWork = workflowBpmnService.getNodeExtensionProperty(bpmnModelInstance,
                taskDefineKey, VoteWork.class, VoteWork.class);
        AssertUtils.notTrue(modelElementInstance instanceof UserTask, "撤回失败，非人工节点不能撤回");
        //当前任务是会签
        AssertUtils.notTrue(voteWork == null, "撤回失败，会签不能撤回");

        TaskResponse.TaskResponseBuilder taskResponseBuilder = TaskResponse.builder();
        taskResponseBuilder.activityId(taskDefineKey);
        taskResponseBuilder.processInstanceId(taskInstance.getProcessInstanceId());
        taskResponseBuilder.userId(userId);
        taskResponseBuilder.taskId(taskInstance.getId());
        taskResponseBuilder.taskName(taskInstance.getName());
        taskResponseBuilder.taskDefineKey(taskInstance.getTaskDefinitionKey());
        taskResponseBuilder.startTime(taskInstance.getStartTime());
        TaskResponse taskResponse = taskResponseBuilder.build();
        workFlowEngineService.reBackTask(taskResponse);
        // 更新流程状态
        wfSysProcInfoService.update(taskResponse.getProcessInstanceId(), DeleteReasonConstants.TAKEBACK,
                null, Constants.Flag.FALSE);
        return taskResponse;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public TaskResponse backToFirstUserTask(ProcessTaskRequest request, String processStatus) {
        TaskResponse.TaskResponseBuilder taskResponseBuilder = TaskResponse.builder();
        String userId = this.getCurrentUserId();
        AssertUtils.notEmpty(request.getTaskId(), ErrorMessageConstants.TASK_ID_NOE_NULL);
        Task task = workflowTaskService.findTask(request.getTaskId());
        AssertUtils.notNull(task, ErrorMessageConstants.TASK_NOE_EXIST);
        workflowTaskService.checkAndClaimTask(userId, request.getTaskId());
        taskResponseBuilder.activityId(task.getTaskDefinitionKey());
        taskResponseBuilder.processInstanceId(task.getProcessInstanceId());

        //查询第一个审批节点
        List<HistoricTaskInstance> firstTask = workflowInstanceService.queryFirstHistoryTaskInstance(task.getProcessInstanceId());
        AssertUtils.notTrue(CollectionUtils.isNotEmpty(firstTask), "无法回退到首个用户任务");
        List<String> nextActivityIds = new ArrayList<>();
        nextActivityIds.add(firstTask.get(0).getTaskDefinitionKey());
        taskResponseBuilder.nextActivityIds(nextActivityIds);
        taskResponseBuilder.userId(userId);
        taskResponseBuilder.taskId(task.getId());
        taskResponseBuilder.taskName(task.getName());
        taskResponseBuilder.taskDefineKey(task.getTaskDefinitionKey());
        taskResponseBuilder.comment(request.getComment());
        taskResponseBuilder.variables(request.getGlobalVariables());
        TaskResponse taskResponse = taskResponseBuilder.build();
        workFlowEngineService.backTask(taskResponse, processStatus);
        // 更新流程状态
        wfSysProcInfoService.update(task.getProcessInstanceId(), processStatus,
                null, Constants.Flag.FALSE);
        HistoricProcessInstance processInstance = workflowInstanceService
                .queryHistoryProcessInstance(task.getProcessInstanceId());
        WfSysProcInfoEntity wfSysProcInfoEntity = getProcInfo(request.getProcessInstanceId(),request.getComment());
        WfTaskAnnotationService wfTaskAnnotationService = workflowAnnotation.getService(processInstance.getProcessDefinitionKey());
        wfTaskAnnotationService.backToFirstUserTask(wfSysProcInfoEntity);
        return taskResponse;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public TaskResponse transferTask(ProcessTaskRequest request) {
        AssertUtils.notNull(request.getTransferUser(), "调度用户不能为空");
        UserInfo userInfo = this.getCurrentUserInfo();
        String cropId = userInfo.getCorpId();
        TaskResponse.TaskResponseBuilder taskResponseBuilder = TaskResponse.builder();
        AssertUtils.notEmpty(request.getTaskId(), ErrorMessageConstants.TASK_ID_NOE_NULL);
        Task task = workflowTaskService.findTask(request.getTaskId());
        AssertUtils.notNull(task, ErrorMessageConstants.TASK_NOE_EXIST);
//        workflowTaskService.checkAndClaimTask(userId, request.getTaskId());
        trackTransfer(request, userInfo, task);
        taskResponseBuilder.taskId(task.getId());
        taskResponseBuilder.taskName(task.getName());
        taskResponseBuilder.taskDefineKey(task.getTaskDefinitionKey());
        taskResponseBuilder.tenantId(cropId);
        taskResponseBuilder.processInstanceId(task.getProcessInstanceId());
        taskResponseBuilder.processDefineId(task.getProcessDefinitionId());
        taskResponseBuilder.activityId(task.getTaskDefinitionKey());
        taskResponseBuilder.transferUser(request.getTransferUser());
        TaskResponse taskResponse = taskResponseBuilder.build();
        workFlowEngineService.transferAssignee(taskResponse);
        // 更新流程状态
        wfSysProcInfoService.update(task.getProcessInstanceId(), DeleteReasonConstants.PROCESS,
                null, Constants.Flag.FALSE);
        return taskResponse;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public TaskResponse transferTask2Others(ProcessTaskRequest request) {
        AssertUtils.notNull(request.getTransferUserList(), "调度用户不能为空");
        UserInfo userInfo = this.getCurrentUserInfo();
        String cropId = userInfo.getCorpId();
        TaskResponse.TaskResponseBuilder taskResponseBuilder = TaskResponse.builder();
        AssertUtils.notEmpty(request.getTaskId(), ErrorMessageConstants.TASK_ID_NOE_NULL);
        Task task = workflowTaskService.findTask(request.getTaskId());
        AssertUtils.notNull(task, ErrorMessageConstants.TASK_NOE_EXIST);
        taskResponseBuilder.taskId(task.getId());
        taskResponseBuilder.taskName(task.getName());
        taskResponseBuilder.taskDefineKey(task.getTaskDefinitionKey());
        taskResponseBuilder.tenantId(cropId);
        taskResponseBuilder.processInstanceId(task.getProcessInstanceId());
        taskResponseBuilder.processDefineId(task.getProcessDefinitionId());
        taskResponseBuilder.activityId(task.getTaskDefinitionKey());
        taskResponseBuilder.transferUser(request.getTransferUser());
        TaskResponse taskResponse = taskResponseBuilder.build();
        workFlowEngineService.transferAssigneeList(taskResponse);
        return taskResponse;
    }

    @Override
    public void submitByStart(ProcessTaskRequest request) {
        String userId = this.getCurrentUserId();
        AssertUtils.notEmpty(request.getProcessInstanceId(), "实例id不能为空");
        WfSysProcInfoEntity wfSysProcInfoEntity = wfSysProcInfoService.selectOne(request.getProcessInstanceId());
        AssertUtils.notTrue(userId.equals(wfSysProcInfoEntity.getStartUserId()), "暂无权限");
        //判断当前任务是否是第一个节点
        List<HistoricTaskInstance> firstTask = workflowInstanceService.queryFirstHistoryTaskInstance(request.getProcessInstanceId());
        AssertUtils.notTrue(CollectionUtils.isNotEmpty(firstTask), "无法回退到首个用户任务");
        List<Task> task = workflowTaskService.findTaskList(request.getProcessInstanceId());
        AssertUtils.notTrue(CollectionUtils.isNotEmpty(task), "当前无进行中的任务");
        Task firstTaskEntity = task.get(0);
        AssertUtils.notTrue(firstTask.get(0).getTaskDefinitionKey().equals(firstTaskEntity.getTaskDefinitionKey()), "审批已被处理");
        request.setTaskId(task.get(0).getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public TaskResponse reBackByStart(ProcessTaskRequest request) {
        String userId = this.getCurrentUserId();
        AssertUtils.notEmpty(request.getProcessInstanceId(), "实例id不能为空");
        WfSysProcInfoEntity wfSysProcInfoEntity = wfSysProcInfoService.selectOne(request.getProcessInstanceId());
        AssertUtils.notTrue(userId.equals(wfSysProcInfoEntity.getStartUserId()), "暂无权限");
        List<Task> tasks = workflowTaskService.findTaskList(request.getProcessInstanceId());
        AssertUtils.notTrue(CollectionUtils.isNotEmpty(tasks), "当前无进行中的任务");
        AssertUtils.notTrue(tasks.size() == 1, "撤回失败，当前环节有多个待办任务，不能撤回");
        Task firstTaskEntity = tasks.get(0);
        request.setTaskId(firstTaskEntity.getId());
        WorkflowThreadLocalUtil.put("deleteReasonProcInstId", firstTaskEntity.getProcessInstanceId());
        WorkflowThreadLocalUtil.put("deleteReasonTaskId", firstTaskEntity.getId());
        WorkflowThreadLocalUtil.put("deleteReason", DeleteReasonConstants.FIRSTTASKBACK);
        return backToFirstUserTask(request,DeleteReasonConstants.FIRSTTASKBACK);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result batchSubmitTask(List<ProcessTaskRequest> requests) {
        int successCount = 0;
        int errorCount = 0;
        for (ProcessTaskRequest request : requests) {
            try{
                request.setActivityId(null);
                submitTask(request, DeleteReasonConstants.PROCESS);
                successCount++;
            }catch (Exception e) {
                log.error("批量通过异常，入参：{}  异常：{}", JSON.toJSONString(request), e);
                errorCount++;
            }
        }
        Map<String, Object> params = new HashMap<>();
        params.put("total", requests.size());
        params.put("successCount", successCount);
        params.put("errorCount", errorCount);
        return Result.ok(params);
    }

    @Override
    public Result batchRefuseTask(List<ProcessTaskRequest> requests) {
        int successCount = 0;
        int errorCount = 0;
        for (ProcessTaskRequest request : requests) {
            try{
                request.setActivityId(null);
                refuseTask(request);
                successCount++;
            }catch (Exception e) {
                log.error("批量通过异常，入参：{}  异常：{}", JSON.toJSONString(request), e);
                errorCount++;
            }
        }
        Map<String, Object> params = new HashMap<>();
        params.put("total", requests.size());
        params.put("successCount", successCount);
        params.put("errorCount", errorCount);
        return Result.ok(params);
    }

    @Override
    public Result getApprovalTypeCount(ProcessTaskRequest request) {
        if ("todo".equals(request.getType())) {
            UserInfo userInfo = this.getCurrentUserInfo();
            TodoTaskQuery taskQuery = ProcTaskAssembler.createTodoTaskQuery(new ProcessTaskRequest(), userInfo);
            return Result.ok(taskQuery.countProcDefKey());
        } else if ("done".equals(request.getType())) {
            UserInfo userInfo = this.getCurrentUserInfo();
            CompleteTaskQuery taskQuery = ProcTaskAssembler.createCompleteTaskQuery(new ProcessTaskRequest(), userInfo);
            return Result.ok(taskQuery.countProcDefKey());
        } else if ("mine".equals(request.getType())) {
            UserInfo userInfo = this.getCurrentUserInfo();
            MyApplyTaskQuery taskQuery = ProcTaskAssembler.createMyApplyTaskQuery(new ProcessTaskRequest(), userInfo);
            return Result.ok(taskQuery.countProcDefKey());
        }
        return Result.OK_EMPTY;
    }

    /**
     * 遍历获取用户节点
     * @param flowNode flowNode
     * @return List<UserTask>
     */
    private List<UserTask> getPreviousUserTask(FlowNode flowNode) {
        List<UserTask> userTasks = new ArrayList<>();
        List<FlowNode> list = flowNode.getPreviousNodes().list();
        for (FlowNode node : list) {
            if (node instanceof UserTask) {
                userTasks.add((UserTask) node);
            } else {
                userTasks.addAll(getPreviousUserTask(node));
            }
        }
        return userTasks;
    }

    private void trackTransfer(ProcessTaskRequest request, UserInfo userInfo, Task task) {
        Object transferTrack = workflowTaskService.getVariableLocal(task.getId(), Constants._TRANSFER_TRACK);
        Map<String, Object> track = new HashMap<>(1);
        track.put("endTime", DateUtils.dateToStr(new Date()));
        track.put("comment", request.getComment());
        track.put("assignee", userInfo.getUserId());
        track.put("assigneeName", userInfo.getUserName());
        track.put("localVariables", request.getLocalVariables());
        track.put("deleteReason", DeleteReasonConstants.TRANSFER);
        if (transferTrack != null) {
            Map<String, Object> next = (Map) transferTrack;
            Object last = null;
            while ((last = next.get("next")) != null) {
                next = (Map) last;
            }
            next.put("next",track);
        } else {
            transferTrack = track;
        }
        workflowTaskService.setVariableLocalByKey(task.getId(), Constants._TRANSFER_TRACK, transferTrack);
    }

    /**
     * 根据流程实例获取流程信息
     * @param procInstId procInstId
     * @return WfSysProcInfoEntity
     */
    private WfSysProcInfoEntity getProcInfo(String procInstId, String comment) {
        WfSysProcInfoEntity wfSysProcInfoEntity = wfSysProcInfoService.selectOne(procInstId);
        if (wfSysProcInfoEntity != null && StringUtils.isNotBlank(wfSysProcInfoEntity.getParamMap())) {
            Map<String, Object> paramMap = JSON.parseObject(wfSysProcInfoEntity.getParamMap());
            wfSysProcInfoEntity.setParamMaps(paramMap);
            wfSysProcInfoEntity.setExtensionData(JSON.parseObject(JSON.toJSONString(paramMap.get(Constants.EXTENSION_DATA))));
            wfSysProcInfoEntity.setComment(comment);
        }
        return wfSysProcInfoEntity;
    }
}
